/**
 * require 模块加载器 hjs
 * 参考 CommonJS 模块化规范实现的简化版模块加载器，支持模块嵌套使用，使用时需首先引入require.js.
 * 
 * 基本原理：
 *   将模块js内容缓存到内存中，通过注册的mod名称进行调用，首先需要将js引入页面.
 * 使用示例：
    <script src="require.js"></script>
    <script>
        //注册模块
        require.define("mod", function(exports, require, module){
            //exports: 当前定义模块的导出对象，即 module.exports 
            //require: 当前定义的模块内部使用的 require 加载器，使用方式同全局 require 
            //module: 已注册的模块对象

            var mod = require('xxx');

            var init = function(){
                mod.somthing();
            };
            exports.init = init;
        })

        //使用模块
        var m = require('mod');
        m.init();
    </script>
 */

(function () {
    'use strict';

    //如果已存在 require ，不重复创建
    var globals = window ? window : global;
    if (typeof globals.require === 'function') return console.warn('require has been loaded !');

    /**
     * 注册的模块对象集合
     */
    var _definedModules = {};


    /**
     * 模块参数
     * @param {boolean} error       是否打印异常
     * @param {boolean} throw       是否抛出异常
     */
    var _defineConfig = {
        error: false,
        throw: false,
    };

    /**
     * 模块对象
     */
    var Module = {
        _load: function (request, parent) {
            try {
                var name = Module._resolveFilename(request, parent);
                var definition = _definedModules[name];
                if (!definition) throw new Error('Cannot find module "' + name + '" from ' + '"' + parent + '"');

                if (Module._cache[name]) return Module._cache[name].exports;
                var localRequire = createLocalRequire(name);
                var module = { id: name, exports: {} };
                Module._cache[name] = module;
                definition.call(module.exports, module.exports, localRequire, module);
                return module.exports;
            } catch (e) {
                if (_defineConfig.error) console.error(e);
                if (_defineConfig.throw) throw e;
            }
        },
        _cache: {},
        //模拟Node环境功能的处理
        _resolveFilename: function (request, parent) {
            try {
                var path = expand(dirname(parent), request);
                if (_definedModules.hasOwnProperty(path)) return path;
                path = expand(path, './index');
                if (_definedModules.hasOwnProperty(path)) return path;
                return request;
            } catch (e) {
                if (_defineConfig.error) console.error(e);
                if (_defineConfig.throw) throw e;
            }
        }
    };

    /**
     * 解析路径or名称
     * @returns {string} 解析后的路径
     */
    var expand = (function () {
        var reg = /^\.\.?(\/|$)/;
        return function (root, name) {
            var results = [], parts, part;
            parts = (reg.test(name) ? root + '/' + name : name).split('/');
            for (var i = 0, length = parts.length; i < length; i++) {
                part = parts[i];
                if (part === '..') {
                    results.pop();
                } else if (part !== '.' && part !== '') {
                    results.push(part);
                }
            }
            return results.join('/');
        };
    })();

    /**
     * 引入内部加载器
     * @param {any} parent  父级模块加载器
     */
    var createLocalRequire = function (parent) {
        return function (name) {
            return globals.require(name, parent);
        };
    };

    /**
     * 注册路径名称处理
     * @param {string} path 路径字符串
     * @returns {string} 处理后的路径
     */
    var dirname = function (path) {
        if (!path) return '';
        return path.split('/').slice(0, -1).join('/');
    };

    /**
     * 载入模块
     * @param {string} name         注册的模块名称
     * @param {string} loaderPath   注册的模块父路径（可选）
     */
    var require = function (name, loaderPath) {
        return Module._load(name, loaderPath);
    };

    /**
     * 注册模块，可使用 define 或 require.define 或别名 require.register 进行模块注册
     * @param {string} bundle   绑定器
     * @param {string} calfnc   回调函数，如果绑定的是函数，则进行回调，否则直接输出对象
     */
    require.register = require.define = function (bundle, calfnc) {
        try {

            if (arguments.length == 1) {
                if (typeof arguments[0] === 'object') {
                    for (var key in arguments[0]) {
                        if (bundle.hasOwnProperty(key)) {
                            _definedModules[key] = arguments[0][key];
                        }
                    }
                }
            } else if (arguments.length == 2) {
                if(typeof arguments[0] === 'string') {
                    _definedModules[arguments[0]] = arguments[1];
                }
            } else if (arguments.length == 3) {
                if (typeof arguments[0] === 'string' && typeof arguments[1] !== 'string') {
                    _definedModules[arguments[0]] = arguments[1];
                }
                if (typeof arguments[0] === 'string' && typeof arguments[1] === 'string') {
                    var bundle = arguments[0] + '.' + arguments[1];
                    _definedModules[bundle] = arguments[2];
                }
            }
        } catch (e) {
            if (_defineConfig.error) console.error(e);
            if (_defineConfig.throw) throw e;
        }
    };

    /**
     * require 配置参数
     * @param {boolean} error       是否打印异常
     * @param {boolean} throw       是否抛出异常
     */
    require.config = {
        get error() {
            return _defineConfig.error;
        },
        set error(v) {
            _defineConfig.error = v;
        },
        get throw() {
            return _defineConfig.throw;
        },
        set throw(v) {
            _defineConfig.throw = v;
        }
    };

    /**
     * 获取已注册的模块名称列表
     * @returns {Array} 模块列表集合
     */
    require.list = function () {
        var result = [];
        for (var item in _definedModules) {
            if (_definedModules.hasOwnProperty(item)) {
                result.push(item);
            }
        }
        return result;
    };

    /**
     * 生成随机值字符串
     * @param {Number} len     字符长度
     * @param {Number} radix   进制数 16/32/64，默认64位
     * @returns {string} 随机字符串
     */
    require.random = function (len, radix) {
        var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
        var uuid = [], i;
        radix = radix || chars.length;
        if (len) {
            for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
        } else {
            var r;
            uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
            uuid[14] = '4';
            for (i = 0; i < 36; i++) {
                if (!uuid[i]) {
                    r = 0 | Math.random() * 16;
                    uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
                }
            }
        }
        return uuid.join('');
    };

    var _moduleid = require.random();
    /**
     * 模块对象注册
     */
    require.define(_moduleid, function (exports, require, module) {
        module.exports = Module;
    });

    /**
     * 创建 require 加载器到global全局
     */
    if (!globals.require) {
        globals.require = require;
        if (!globals.define) {
            globals.define = require.define;
        }
    }
})();